﻿using Centny.PdfReader.IO;
using Centny.PdfReader.Pdf;
using Centny.PdfReader.Types;
using Centny.PdfReader.util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;

namespace Centny.PdfReader.Font
{
    public enum PdfFontType
    {
        Type0, Type1, MMType1, Type3, TrueType, CIDFontType0, CIDFontType2
    }
    public class PdfFont : PdfIDocumentVisible
    {
        public PdfClassObject Font { get; set; }
        public PdfName BaseFont { get; set; }
        public PdfDictionary FontDescriptor { get; set; }
        public PdfArray Widths { get; set; }
        public PdfStreamObject FontFile { get; set; }
        public double FontSize { get; set; }
        public PdfDocument Doc { get; set; }
        public PdfFontType FontType { get; set; }
        public double Scale { get; set; }
        public bool IsValid { get; set; }
        public double RealFontSize
        {
            get
            {
                return this.FontSize * this.Scale;
            }
        }
        public PdfFont(PdfDocument doc, PdfClassObject font, double fsize, double scale)
        {
            this.Doc = doc;
            this.Font = font;
            this.FontSize = fsize;
            this.Scale = scale;
            this.BaseFont = this.Font[FontKeys.BaseFont] as PdfName;
            PdfName stype = this.Font[FontKeys.Subtype] as PdfName;
            if (stype != null)
            {
                PdfFontType _ft;
                this.IsValid = Enum.TryParse<PdfFontType>(stype.NName, out _ft);
                if (this.IsValid)
                {
                    this.FontType = _ft;
                    switch (this.FontType)
                    {
                        case PdfFontType.Type1:
                        case PdfFontType.MMType1:
                            this.InitType1();
                            break;
                    }
                }
            }
            else
            {
                this.IsValid = false;
            }
        }

        private void InitType1()
        {
            PdfClass cls;
            cls = this.Font[FontKeys.FontDescriptor];
            if (cls is PdfReference)
            {
                //PdfTimer.SharedTimer.Beg();
                PdfClassObject cobj = this.Doc.RealObject(cls as PdfReference) as PdfClassObject;
                this.FontDescriptor = cobj.AsDictionary;
                this.Doc.StoreObject(cls as PdfReference, cobj);
                //PdfTimer.SharedTimer.End("FontDescriptor");
            }
            else if (cls is PdfDictionary)
            {
                this.FontDescriptor = cls as PdfDictionary;
            }
            if (this.FontDescriptor != null)
            {
                //PdfTimer.SharedTimer.Beg();
                PdfReference pref = this.FontDescriptor[FontDescKeys.FontFile] as PdfReference;
                if (pref != null)
                {
                    this.FontFile = this.Doc.RealObject(pref) as PdfStreamObject;
                    this.Doc.StoreObject(pref, this.FontFile);
                }
                //PdfTimer.SharedTimer.End("FontFile");
            }
            cls = this.Font[FontKeys.Widths];
            if (cls is PdfReference)
            {
                //PdfTimer.SharedTimer.Beg();
                PdfClassObject cobj = this.Doc.RealObject(cls as PdfReference, PdfLexer.AryValType(FontKeys.Widths)) as PdfClassObject;
                //PdfTimer.SharedTimer.End("Widths");
                this.Doc.StoreObject(cls as PdfReference, cobj);
                this.Widths = cobj.AsArray;
            }
            else if (cls is PdfArray)
            {
                this.Widths = cls as PdfArray;
            }
        }
        public virtual Size GlyphSize(char c)
        {
            switch (this.FontType)
            {
                case PdfFontType.MMType1:
                case PdfFontType.Type1:
                    Size csize = this.CountGlyphSize(c);
                    if (csize.Width < 1)
                    {
                        return csize;
                    }
                    PdfLong fc = this.Font[FontKeys.FirstChar] as PdfLong;
                    PdfLong lc = this.Font[FontKeys.LastChar] as PdfLong;
                    int idx = (int)(c - fc.AsLong);
                    if (fc != null && lc != null && c > fc.AsLong && c < lc.AsLong)
                    {
                        csize.Width = (this.Widths[idx] as PdfLong).Val / 1000.0f * this.FontSize;
                        csize.Width *= this.Scale;
                    }
                    else
                    {
                        csize.Width *= 0.8;
                    }
                    csize.Height *= 0.8;
                    return csize;
                default:
                    throw new NotImplementedException(this.FontType + " not implemented");

            }
        }
        public virtual Size CountGlyphSize(char c)
        {
            throw new NotImplementedException("GlyphSize");
        }
    }
}
